package com.ebs.md.fxmonitor.client.impl;

/**
 * Revision Author:
 *  $File: //depot/MarketData/fxmonitor/main/src/main/java/com/ebs/md/fxmonitor/client/impl/FixingListWrapper.java $
 *  $Revision: #3 $
 *  $DateTime: 2012/03/07 13:28:52 $
 *  $Change: 109041 $
 *  $Author: Arik.Sher $
 */

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.QueueBrowser;
import javax.jms.QueueConnection;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.ebs.commons.comp.IJmsConnectionProvider;
import com.ebs.commons.comp.IParsedPayload;
import com.ebs.commons.comp.ParsedPayload;
import com.ebs.commons.db.DataSourceException;
import com.ebs.commons.db.SPLoader;

public class FixingListWrapper implements Runnable, ExceptionListener, MessageListener
{
    
    private QueueConnection m_fixingQueueConnection;
    private QueueSession m_fixingQueueReceiveSession;
    private MessageConsumer m_fixingQueueReceiver;
    
    private SPLoader m_spLoader;
    
	private IJmsConnectionProvider m_FixingConnectionProvider;
	private String m_fixingResponseQueueName = "PROD.FX.1_0.CCC.FSP.X.CCC";
	    
    final static Logger s_logger = Logger.getLogger(FixingListWrapper.class);
    
    FixingListWrapper()
    {
    }
    
    public void setSpLoader(SPLoader spLoader)
    {
    	m_spLoader = spLoader;
    }    
    
    
    public void setConsumerConnectionProvider(IJmsConnectionProvider connectionProvider)
    {
    	m_FixingConnectionProvider = connectionProvider;
    }
    
    public void setFixingQueueName(String fixingQueueName)
    {
    	m_fixingResponseQueueName = fixingQueueName;
    }
    
    public void run()
    {        	        	
    	if(!connectToFixingListQueue())
    	{
    		return;
    	}
    }
    
    public void archiveFixList(IParsedPayload fixingListPayload)
    {
    	Map<String,Object> params = new HashMap<String,Object>();
    	try
    	{
    		Map<String,Object> params_init = fixingListPayload.getParsedMessage();        		
    		for(String nextKey : params_init.keySet())
    		{
    			params.put(nextKey.toUpperCase(), params_init.get(nextKey));
    		}
    		s_logger.info("FixingListWrapper archiveFixList params:" + params);
    		List<Map<String,Object>> result = m_spLoader.getRecordSet(params);
    		s_logger.info("FixingListWrapper archiveFixList result:" + result);
    	}
        catch(DataSourceException dse) 
        {                                    
            s_logger.error("FixingListWrapper exception archiving fix list. params:" + params, dse);
        }
    	catch(Exception e)
    	{
    		s_logger.error("FixingListWrapper exception archiving fix list. params:" + params, e);
    	}
    }
    
    
    
    public Message GetSynchResponse(int retryNumber, int waitMsecValue)
    {
    	Message toReturn = null;
    	if(m_fixingQueueReceiver == null)
    	{
    		return toReturn;
    	}
    	int currentRetry = 0;
    	while((currentRetry < retryNumber) && (toReturn == null))
    	{
    		try
    		{
    			toReturn = m_fixingQueueReceiver.receive(waitMsecValue);
    		}
    		catch(Exception e)
    		{
    			s_logger.error("FixingListWrapper GetSynchResponse exception:",e);
    			currentRetry = retryNumber;
    		}        		
    		currentRetry++;
    	}
    	return toReturn;
    }
    
    
    public synchronized void onMessage(Message theMessage)
    {    	
//    	try
//    	{    	
//    		s_logger.info("FixingListWrapper received response message");
//    		String responseXML = ((TextMessage)theMessage).getText();
//    		s_logger.info("FixingList:" + responseXML);
//    		theMessage.acknowledge();
//    		theMessage = null;
//    		IParsedPayload fixingListPayload = new ParsedPayload();
//    		if(processFixingList(responseXML, fixingListPayload))
//    		{
//    			fixingListPayload.addField("mq_msg_type", "NFIT");
//    			fixingListPayload.addField("msg_version", "01");
//    			fixingListPayload.addField("recovery_current_flag", "1");
//    			fixingListPayload.addField("sp_name", "ARCHIVE_FIX_LIST");
//    			sendDataToTraiana(fixingListPayload, m_sourceName + System.currentTimeMillis(), false);
//    			Map<String,Object> params_init = fixingListPayload.getParsedMessage();
//    			Map<String,Object> params = new HashMap<String,Object>();
//    			for(String nextKey : params_init.keySet())
//    			{
//    				params.put(nextKey.toUpperCase(), params_init.get(nextKey));
//    			}
//    			s_logger.info("params:" + params);
//    			List<Map<String,Object>> result = m_spLoader.getRecordSet(params);
//    			s_logger.info("result:" + result);
//    			System.out.println("result:" + result);
//    		}        		
//    	}
//		catch(JMSException jmse)
//		{
//			s_logger.error("MQPublicator JMSException:",jmse);
//			jmse.printStackTrace();
//		}
//		catch(Exception e)
//		{
//			s_logger.error("MQPublicator Exception:",e);
//			e.printStackTrace();
//		}
//		resetFixingConnection();
    }
    

    
	public void onException(JMSException jmse)
	{
		s_logger.info("FixingListWrapper Received JMSException from MQ ",jmse);
		jmse.printStackTrace();
	}
    
    public boolean  connectToFixingListQueue()
    {
    	boolean toReturn = false;
    	
    	try
    	{
    		s_logger.info("FixingListWrapper begin connectToFixingListQueue()");
    		
    		resetFixingConnection();
    		
    		s_logger.info("FixingListWrapper going to create Queue Connection for Fixing");
    		m_fixingQueueConnection = (QueueConnection)m_FixingConnectionProvider.getConnection();
    		s_logger.info("FixingListWrapper going to createQueueSession");
    		m_fixingQueueReceiveSession = (QueueSession)m_FixingConnectionProvider.getSession(m_fixingQueueConnection);
    		s_logger.info("FixingListWrapper going to create receiving queue name:" + m_fixingResponseQueueName);
    		QueueBrowser qb = m_fixingQueueReceiveSession.createBrowser(m_fixingQueueReceiveSession.createQueue(m_fixingResponseQueueName),"cfgsubject='Fixings'");
    		m_fixingQueueConnection.start();
    		Enumeration en = qb.getEnumeration();
    		if(!en.hasMoreElements())
    		{
    			s_logger.info("FixingListWrapper: No FIXing configurations in the queue");        			
    		}
    		else
    		{
    			TreeMap<Long,String> fixings = new TreeMap<Long, String>();
    			while(en.hasMoreElements())
    			{        				
    				TextMessage nextMessage = (TextMessage)en.nextElement(); 
//    				String confSubject = nextMessage.getStringProperty("cfgsubject");
//    				if(confSubject.equalsIgnoreCase("Fixings"))
//    				{
    					Long version = nextMessage.getLongProperty("cfgtime");        					
    					fixings.put(version, nextMessage.getText());
//    				}
    			}
    			s_logger.info("Total number of Fixings:" + fixings.size());
    			s_logger.info("lastKey:" + fixings.lastKey() + " firstKey" + fixings.firstKey());
    			if(fixings.size() > 0)
    			{
    				processFixingMessage(fixings);
    			}
    			else
    			{
    				s_logger.error("There is no one Fixing configuration in the configuration queue");
    			}
    		}
    	}
    	catch(JMSException jmse)
    	{
    		s_logger.error("FixingListWrapper JMSException creating MQ", jmse);
    	}
    	catch(Exception e)
    	{
    		s_logger.error("FixingListWrapper Exception creating MQ", e);
    	}
    	catch(Throwable t)
    	{
    		s_logger.error("FixingListWrapper Throwable creating MQ", t);
    	}
    	return toReturn;
    }
    
    public synchronized void resetFixingConnection()
    {
    	s_logger.info("FixingListWrapper resetFixingConnection");
    	
    	if(m_fixingQueueReceiver != null)
    	{
    		try
    		{
    			m_fixingQueueReceiver.close();
    		}
    		catch(Exception ignored){}
    		catch(Throwable t){}
    		m_fixingQueueReceiver = null;
    	}   

    	
        if(m_fixingQueueReceiveSession!=null)
        {
        	try
        	{        
        		m_fixingQueueReceiveSession.close();        		
        	}
        	catch(Exception ignored){}
        	catch(Throwable t){}
        	m_fixingQueueReceiveSession = null;
        }
        
        if(m_fixingQueueConnection!=null)
        {
        	try
        	{
        		m_fixingQueueConnection.close();        		
        	}
        	catch(Exception ignored){}
        	catch(Throwable t){}
        	m_fixingQueueConnection = null;
        }
    }
    
    private void processFixingMessage(TreeMap<Long,String> fixings)
    {
		String targetXmlText = fixings.get(fixings.lastKey());
		s_logger.info("FixingListWrapper fixing configuration has been received");
		IParsedPayload fixingListPayload = new ParsedPayload();
		if(processFixingList(targetXmlText, fixingListPayload))
		{
			fixingListPayload.addField("mq_msg_type", "NFIT");
			fixingListPayload.addField("msg_version", "01");
			fixingListPayload.addField("recovery_current_flag", "1");
			fixingListPayload.addField("sp_name", "ARCHIVE_FIX_LIST");
			archiveFixList(fixingListPayload);
		}        	        				
    }
 
    

private boolean processFixingList(String responseXML, IParsedPayload fixingListPayload)       
{
	boolean toReturn = false;
	try
	{
		DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
		builderFactory.setIgnoringElementContentWhitespace(true);
	    DocumentBuilder builder = null;
	    try 
	    {
	      builder = builderFactory.newDocumentBuilder();  // Create the parser
	    } 
	    catch(ParserConfigurationException pce) 
	    {
	      s_logger.error("FixingListWrapper processFixingList ParserConfigurationException:",pce);
	      return toReturn;
	    }
	    Document xmlDoc = null;

	    try 
	    {
	      xmlDoc = builder.parse(new InputSource(new StringReader(responseXML)));
	    } 
	    catch(SAXException saxe) 
	    {
	    	s_logger.error("FixingListWrapper processFixingList SAXException:",saxe);
	    	return toReturn;

	    } 
	    catch(IOException ioe) 
	    {
	    	s_logger.error("FixingListWrapper processFixingList IOException:",ioe);
	    	return toReturn;
	    }
	    catch(Exception e)
	    {
	    	s_logger.error("FixingListWrapper processFixingList Exception:",e);
	    	return toReturn;
	    }
		
		if(xmlDoc == null)
		{
			s_logger.error("FixingListWrapper processFixingList xmlDoc is NULL");
			return toReturn;
		}
			
		NodeList message_array = xmlDoc.getElementsByTagName("Fixing");
		if(message_array.getLength() > 0)
		{    
			loadFixingXML(message_array, fixingListPayload);
			toReturn = true;
		}
		else
		{
			s_logger.info("Child Notes list size is <= 0");
		}
	}
	catch(Exception e)
	{
		s_logger.error("Exception e:", e);
		e.printStackTrace();
	}
	return toReturn;
}

protected int loadFixingXML(NodeList message_array, IParsedPayload payload)
{
	int toReturn = 0;
    if(null != message_array)
    {
    	int nodes_size = message_array.getLength();
    	toReturn = nodes_size;
    	if(nodes_size > 0)
    	{
    		payload.addField("item_count", nodes_size);	
    		List<String> fix_name = new ArrayList<String>(nodes_size);
    		payload.addField("fix_name_array", fix_name);
    		List<Long> fix_id = new ArrayList<Long>(nodes_size);
    		payload.addField("fix_id_array", fix_id);
    		List<String> fix_source = new ArrayList<String>(nodes_size);
    		payload.addField("fix_source_array", fix_source);
    		List<String> fix_time = new ArrayList<String>(nodes_size);
    		payload.addField("fix_time_array", fix_time);
    		List<String> fix_time_zone = new ArrayList<String>(nodes_size);
    		payload.addField("fix_time_zone_array", fix_time_zone);
    		
    		for(int i = 0; i < nodes_size; i++)
    		{
    			NamedNodeMap nnm = message_array.item(i).getAttributes();

    			String fixIdStr = parseNodeAttributeValue(nnm, "fixId", -12343214/*some dummy value*/);
    			Long   fixId;
    			if((fixIdStr != null)&&(fixIdStr.length()>0)) {
    				fixId = Long.parseLong(fixIdStr);
    			} else {
    				fixId = i*1000L;
    			}
    			fix_id.add(fixId);
    			
    			fix_name     .add(parseNodeAttributeValue(nnm, "name", fixId));
    			fix_source   .add(parseNodeAttributeValue(nnm, "fixSource", fixId));
    			fix_time     .add(parseNodeAttributeValue(nnm, "fixSourceLocalTime", fixId));
    			fix_time_zone.add(parseNodeAttributeValue(nnm, "fixSourceLocalTimeZone", fixId));            			
    		}
    	}
    	else
    	{
    		s_logger.info("loadFixingXML nodes_size is NULL or <= 0");
    	}
    }
    else
    {
    	s_logger.info("loadFixingXML message_array is NULL");
    }
    return toReturn;
}

	/**
	 * 
	 * @param nnm
	 * @param attrName
	 * @param fixId - informative field
	 * @return
	 */
	protected String parseNodeAttributeValue(NamedNodeMap nnm, String attrName, long fixId) {
		if ( nnm == null || attrName == null ) {
			return "";
		}
		
		Node attrItem = nnm.getNamedItem(attrName);
		
		if ( attrItem == null ) {
			s_logger.info(String.format("parseNodeAttributeValue, attr name '%s' could not be found for fixId '%s'", attrName, fixId));
			return "";
		}
		
		return attrItem.getNodeValue();
	}

protected String parseNodeAttributeValue(Element theMessage, String attributeName)
{
    if (theMessage == null)
    {
        return "";
    }
    Node nd = theMessage.getAttributeNode(attributeName);
    if (nd == null)
    {
        return "";
    }
    return nd.getNodeValue();
}    

}

